package com.softsec.isc.analysis;



/**
 * apk signature result
 * @author ������
 * @since 2013-04-27 11:38:00
 */
import java.io.IOException;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import sun.security.x509.CertificateAlgorithmId;
import sun.security.x509.CertificateIssuerName;
import sun.security.x509.CertificateSerialNumber;
import sun.security.x509.CertificateValidity;
import sun.security.x509.CertificateVersion;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;

import com.softsec.tase.common.dto.app.apk.ApkCertificate;
import com.softsec.tase.common.dto.app.apk.ApkCertificates;
import com.softsec.tase.common.dto.app.apk.ApkSignature;

public class ApkSignatureExtractor {

	/**
	 * get apk signature info from apk file
	 * 
	 * @param apkPath
	 * @return apkSignature
	 * @throws ParserException
	 * @throws CertificateException
	 * @throws IOException
	 */
	public static ApkSignature getApkSignature(String apkPath) throws  CertificateException, IOException {

		String certType = null;
		String publicKeyString = null;
		String publicKeyModulus = null;
		String publicExponent = null;
		String algorithm = null;
		int hashCode = 0;
		@SuppressWarnings("unused")
		long publicKeyExponent = 0;
		PublicKey publicKey = null;
		Certificate[] certificates = null;

		ApkSignature apkSignature = null;
		try {
			certificates = CertificateUtils.getCertificates(apkPath);
		} catch (Exception e) {
			
		}

		ApkCertificates apkCertificates = new ApkCertificates();
		List<ApkCertificate> apkCertificateList = new ArrayList<ApkCertificate>();
		if (certificates != null && certificates.length > 0) {
			apkSignature = new ApkSignature();
			for (int i = 0; i < certificates.length; i++) {
				certType = certificates[i].getType();
				if (certType != null && !certType.isEmpty()) {
					apkSignature.setCertificateType(certType);
				}
				publicKey = certificates[i].getPublicKey();
				publicKeyString = publicKey.toString();
				if (publicKeyString != null && !publicKeyString.isEmpty()) {
					Matcher modulusMatcher = Pattern.compile("modulus:\\s+(\\d+)\\s+public").matcher(publicKeyString);
					while (modulusMatcher.find()) {
						publicKeyModulus = modulusMatcher.group(1);
					}
					if (publicKeyModulus != null && !publicKeyModulus.isEmpty()) {
						apkSignature.setPublicKeyModulus(publicKeyModulus);
					}
					Matcher exponentMatcher = Pattern.compile("exponent:\\s+(\\d+)").matcher(publicKeyString);
					while (exponentMatcher.find()) {
						publicExponent = exponentMatcher.group(1);
					}
					if (publicExponent != null && !publicExponent.isEmpty()) {
						// publicKeyExponent=Long.parseLong(publicExponent);
						apkSignature.setPublicKeyExponent(publicExponent);
					}
				}

				algorithm = publicKey.getAlgorithm();
				if (algorithm != null && !algorithm.isEmpty()) {
					apkSignature.setAlgorithm(algorithm);
				}
				hashCode = certificates[i].hashCode();
				apkSignature.setCertificateHashCode(hashCode);
				ApkCertificate apkCertificate = getApkCertificate(certificates[i], publicKeyModulus, publicExponent);
				apkCertificateList.add(apkCertificate);
			}
		}
		apkCertificates.setApkCertificateList(apkCertificateList);
//		apkCertificates.setTimestamp(System.currentTimeMillis());
		apkSignature.setApkCertificates(apkCertificates);
		return apkSignature;
	}

	/**
	 * get apk certificate info from certificate extracted from apk file
	 * 
	 * @param certificate
	 * @param publicKeyModulus
	 * @param publicExponent
	 * @return apkCertificate
	 * @throws CertificateException
	 * @throws IOException
	 */
	private static ApkCertificate getApkCertificate(Certificate certificate, String publicKeyModulus, String publicExponent)
			throws CertificateException, IOException {
		ApkCertificate apkCertificate = new ApkCertificate();
		X509CertInfo cinfo2 = (X509CertInfo) ((X509CertImpl) certificate).get(X509CertImpl.NAME + "." + X509CertImpl.INFO);
		CertificateVersion cversion = (CertificateVersion) cinfo2.get(X509CertInfo.VERSION);
		X500Name csubject = (X500Name) cinfo2.get(X509CertInfo.SUBJECT + "." + CertificateIssuerName.DN_NAME);
		X500Name cissuer = (X500Name) cinfo2.get(X509CertInfo.ISSUER + "." + CertificateIssuerName.DN_NAME);
		CertificateAlgorithmId calgorithm = (CertificateAlgorithmId) cinfo2.get(X509CertInfo.ALGORITHM_ID);
		CertificateSerialNumber csn = (CertificateSerialNumber) cinfo2.get(X509CertInfo.SERIAL_NUMBER);
		CertificateValidity cvalidity = (CertificateValidity) cinfo2.get(X509CertInfo.VALIDITY);
		apkCertificate.setVersion(cversion.toString());
		apkCertificate.setSubject(csubject.toString());
		apkCertificate.setIssuer(cissuer.toString());
		apkCertificate.setPublicExponent(publicExponent);
		apkCertificate.setPublicKeyModulus(publicKeyModulus);
		apkCertificate.setSerialNumber(csn.toString());
		apkCertificate.setAlgorithm(calgorithm.toString());
		apkCertificate.setFromDate(cvalidity.toString());
		apkCertificate.setToDate(cvalidity.toString());
		if (cvalidity.toString() != null && !cvalidity.toString().isEmpty()) {
			Matcher fromDateMatcher = Pattern.compile("(Mon|Tue|Wed|Sat|Fri|Thu|Sun)(.)+(,)").matcher(cvalidity.toString());
			while (fromDateMatcher.find()) {
				// modulusMatcher.group();
				String fromDate = fromDateMatcher.group();
				fromDate = fromDate.substring(0, fromDate.lastIndexOf(","));
				if (fromDate != null) {
					apkCertificate.setFromDate(fromDate);
				}
			}
			Matcher toDateMatcher = Pattern.compile("(Mon|Tue|Wed|Sat|Fri|Thu|Sun)(.)+\\]").matcher(cvalidity.toString());
			while (toDateMatcher.find()) {
				String toDate = toDateMatcher.group();
				toDate = toDate.substring(0, toDate.lastIndexOf("]"));
				if (toDate != null) {
					apkCertificate.setToDate(toDate);
				}
			}
		}
		return apkCertificate;
	}
}
